import 'package:flutter/material.dart';
import 'dart:math' as math;
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';

import 'theme.dart';

typedef void MyButtonCallback();

enum MyButtonStatus{
  Default,
  Push,
  Disable
}

///通用平台按钮，支持文字，图标
class MyButton extends StatefulWidget {
  final double radius;//圆角

  //按钮背景色
  final Color  normalColor;
  final Color  pushColor;
  final Color  disableColor;

  //按钮边框颜色
  final Color  normalBorderColor;
  final Color  pushBorderColor;
  final Color  disableBorderColor;
  final double borderSize;

  //文本颜色
  final Color  textColor;
  final Color  textPushColor;
  final Color  textDisableColor;
  final double textSize;
  
  final double vpadding;
  final double hpadding;

  final Widget icon;//图标
  final bool   flex;//是否自适应宽度

  final String title;
  final bool   enable;

  //事件
  final MyButtonCallback onTapDown;
  final MyButtonCallback onTapUp;
  final MyButtonCallback onTap;
  final MyButtonCallback onTapCancel;
  final MyButtonCallback onDoubleTap;
  final MyButtonCallback onLongPress;

  MyButton({
    Key key,
    this.title,
    this.radius:5.0,
    this.normalColor:Colors.lightBlue,
    this.pushColor:Colors.blue,
    this.disableColor:const Color(0xFFE0E0E0),
    this.normalBorderColor,
    this.pushBorderColor,
    this.disableBorderColor,
    this.textColor:Colors.white,
    this.textPushColor:Colors.white70,
    this.textDisableColor:const Color(0xFF909090),
    this.textSize:13.0,
    this.borderSize,
    this.icon,
    this.flex:false,
    this.onTapDown,
    this.onTapUp,
    this.onTap,
    this.onTapCancel,
    this.onDoubleTap,
    this.onLongPress,
    this.vpadding:5.0,
    this.hpadding:10.0,
    this.enable:true
  }):super(key:key);

  MyButton.fromTheme({
    MyButtonThemeData theme,
    this.icon,
    this.title,
    this.onTapDown,
    this.onTapUp,
    this.onTap,
    this.onTapCancel,
    this.onDoubleTap,
    this.onLongPress,
    this.enable:true
  }):radius=theme.radius,
    normalColor=theme.normalColor,
    pushColor=theme.pushColor,
    disableColor=theme.disableColor,
    normalBorderColor=theme.normalBorderColor,
    pushBorderColor=theme.pushBorderColor,
    disableBorderColor=theme.disableBorderColor,    
    textColor=theme.textColor,
    textPushColor=theme.textPushColor,
    textDisableColor=theme.textDisableColor,
    textSize=theme.textSize,
    borderSize=theme.borderSize,
    vpadding=theme.vpadding,
    hpadding=theme.hpadding,
    flex=theme.flex;

  @override
  _MyButtonState createState() => _MyButtonState();
}



class _MyButtonState extends State<MyButton> {

  MyButtonStatus _state=MyButtonStatus.Default;

  @override
  void initState(){
    super.initState();
    if(!widget.enable)
      _state = MyButtonStatus.Disable;
  }

  void setButtonState(MyButtonStatus state){
    setState(() {
      _state=state;
     });
  }

  Widget _buildChild(BuildContext context){
    Color color;
    switch(_state)
    {
      case MyButtonStatus.Push:
        color = widget.textPushColor;
        break;
      case MyButtonStatus.Disable:
        color = widget.textDisableColor;
        break;
      default:
        color=widget.textColor;
    }

    EdgeInsets padding = EdgeInsets.symmetric(vertical:widget.vpadding,
                                horizontal:widget.hpadding);

    if(widget.flex)
    {
      if(widget.icon==null)
      {
        return Flex(
          mainAxisAlignment: MainAxisAlignment.center,
          direction:Axis.horizontal,
          children:[
            Padding(
              padding:padding,
              child:Text(
                widget.title,
                style: TextStyle(
                  color:color,
                  fontSize:widget.textSize
                ),
              ),
            )
          ] 
        );
      }
      else{
        return Flex(
          mainAxisAlignment: MainAxisAlignment.center,
          direction:Axis.horizontal,
          children:[
            Padding(
              padding: padding,
              child:Row(
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  widget.icon,
                  SizedBox(width: 3.0),
                  Text(
                    widget.title,
                    style: TextStyle(
                      color:color,
                      fontSize:widget.textSize
                    ),
                  )
                ],
              )
            )
          ]
        );
      }
    }
    else
    {
      if(widget.icon==null)
      {
        return Padding(
          padding:padding,
          child: Text(
            widget.title,
            style: TextStyle(
              color:color,
              fontSize:widget.textSize
            ),
          ),
        );
      }
      else{
        return Padding(
          padding:padding,
          child:Row(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              widget.icon,
              SizedBox(width: 3.0),
              Text(
                widget.title,
                style: TextStyle(
                  color:color,
                  fontSize:widget.textSize
                ),
              )
            ],
          )
        );
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    Color bkColor;
    Color bolderColor;
    switch(_state)
    {
      case MyButtonStatus.Push:
        bkColor = widget.pushColor;
        bolderColor = widget.pushBorderColor;
        break;
      case MyButtonStatus.Disable:
        bkColor = widget.disableColor;
        bolderColor = widget.disableBorderColor;
        break;
      default:
        bkColor = widget.normalColor;
        bolderColor = widget.normalBorderColor;
    }

    ShapeBorder shapeBorder;
    BorderRadius radius;
    if(bolderColor!=null && widget.borderSize!=null && widget.borderSize>0)
    {
      shapeBorder=new RoundedRectangleBorder(
        borderRadius:BorderRadius.all(Radius.circular(widget.radius)),
        side:BorderSide(
          color:bolderColor,
          width: widget.borderSize,
        )
      );
    }
    else
    {
      radius=BorderRadius.all(Radius.circular(widget.radius));
    }

    return Material(
      type:bkColor==null? MaterialType.transparency:MaterialType.button,
      color:bkColor,
      borderRadius:radius,
      shape:shapeBorder,
      child: GestureDetector(
        child:_InputPadding(child:_buildChild(context),
          minSize:Size.zero
        ),
        onTapDown: (dynamic){
          if(_state!=MyButtonStatus.Disable)
          {
            setButtonState(MyButtonStatus.Push);
            if(widget.onTapDown!=null)
              widget.onTapDown();
          }
        },
        onTapUp:(dynamic){
          if(_state!=MyButtonStatus.Disable)
          {
            setButtonState(MyButtonStatus.Default);
            if(widget.onTapUp!=null)
              widget.onTapUp();
          }
        },
        onTapCancel: (){
          if(_state==MyButtonStatus.Push)
          {
            setButtonState(MyButtonStatus.Default);
            if(widget.onTapCancel!=null)
              widget.onTapCancel();            
          }
        },
        onTap: widget.onTap,
        onDoubleTap: widget.onDoubleTap,
        onLongPress: widget.onLongPress,
      ),
    );
  }
}


/// A widget to pad the area around a [MaterialButton]'s inner [Material].
///
/// Redirect taps that occur in the padded area around the child to the center
/// of the child. This increases the size of the button and the button's
/// "tap target", but not its material or its ink splashes.
class _InputPadding extends SingleChildRenderObjectWidget {
  const _InputPadding({
    Key key,
    Widget child,
    this.minSize,
  }) : super(key: key, child: child);

  final Size minSize;

  @override
  RenderObject createRenderObject(BuildContext context) {
    return new _RenderInputPadding(minSize);
  }

  @override
  void updateRenderObject(BuildContext context, covariant _RenderInputPadding renderObject) {
    renderObject.minSize = minSize;
  }
}

class _RenderInputPadding extends RenderShiftedBox {
  _RenderInputPadding(this._minSize, [RenderBox child]) : super(child) ;

  Size get minSize => _minSize;
  Size _minSize;
  set minSize(Size value) {
    if (_minSize == value)
      return;
    _minSize = value;
    markNeedsLayout();
  }

  @override
  double computeMinIntrinsicWidth(double height) {
    if (child != null)
      return math.max(child.computeMinIntrinsicWidth(height), minSize.width);
    return 0.0;
  }

  @override
  double computeMinIntrinsicHeight(double width) {
    if (child != null)
      return math.max(child.computeMinIntrinsicHeight(width), minSize.height);
    return 0.0;
  }

  @override
  double computeMaxIntrinsicWidth(double height) {
    if (child != null)
      return math.max(child.computeMaxIntrinsicWidth(height), minSize.width);
    return 0.0;
  }

  @override
  double computeMaxIntrinsicHeight(double width) {
    if (child != null)
      return math.max(child.computeMaxIntrinsicHeight(width), minSize.height);
    return 0.0;
  }

  @override
  void performLayout() {
    if (child != null) {
      child.layout(constraints, parentUsesSize: true);
      final double height = math.max(child.size.width, minSize.width);
      final double width = math.max(child.size.height, minSize.height);
      size = constraints.constrain(new Size(height, width));
      final BoxParentData childParentData = child.parentData;
      childParentData.offset = Alignment.center.alongOffset(size - child.size);
    } else {
      size = Size.zero;
    }
  }

  @override
  bool hitTest(HitTestResult result, {Offset position}) {
    return super.hitTest(result, position: position) ||
      child.hitTest(result, position: child.size.center(Offset.zero));
  }
}
